6fd16f
@@ -238,14 +238,26 @@
public class RSRpcServices implements HBaseRPCErrorHandler,
    * Holder class which holds the RegionScanner and nextCallSeq together.
    */
   private static class RegionScannerHolder {
+    private AtomicLong nextCallSeq = new AtomicLong(0);
     private RegionScanner s;
-    private long nextCallSeq = 0L;
     private Region r;
 
     public RegionScannerHolder(RegionScanner s, Region r) {
       this.s = s;
       this.r = r;
     }
+
+    private long getNextCallSeq() {
+      return nextCallSeq.get();
+    }
+
+    private void incNextCallSeq() {
+      nextCallSeq.incrementAndGet();
+    }
+
+    private void rollbackNextCallSeq() {
+      nextCallSeq.decrementAndGet();
+    }
   }
 
   /**
@@ -902,7 +914,7 @@
public class RSRpcServices implements HBaseRPCErrorHandler,
     String scannerIdString = Long.toString(scannerId);
     RegionScannerHolder scannerHolder = scanners.get(scannerIdString);
     if (scannerHolder != null) {
-      return scannerHolder.nextCallSeq;
+      return scannerHolder.getNextCallSeq();
     }
     return 0L;
   }
@@ -2225,13 +2237,14 @@
public class RSRpcServices implements HBaseRPCErrorHandler,
             rsh = scanners.get(scannerName);
           }
           if (rsh != null) {
-            if (request.getNextCallSeq() != rsh.nextCallSeq) {
-              throw new OutOfOrderScannerNextException("Expected nextCallSeq: " + rsh.nextCallSeq
+            if (request.getNextCallSeq() != rsh.getNextCallSeq()) {
+              throw new OutOfOrderScannerNextException(
+                "Expected nextCallSeq: " + rsh.getNextCallSeq()
                 + " But the nextCallSeq got from client: " + request.getNextCallSeq() +
                 "; request=" + TextFormat.shortDebugString(request));
             }
             // Increment the nextCallSeq value which is the next expected from client.
-            rsh.nextCallSeq++;
+            rsh.incNextCallSeq();
           }
         }
         try {
@@ -2411,6 +2424,14 @@
public class RSRpcServices implements HBaseRPCErrorHandler,
           } else {
             addResults(builder, results, controller, RegionReplicaUtil.isDefaultReplica(region.getRegionInfo()));
           }
+        } catch (IOException e) {
+          // if we have an exception on scanner next and we are using the callSeq
+          // we should rollback because the client will retry with the same callSeq
+          // and get an OutOfOrderScannerNextException if we don't do so.
+          if (rsh != null && request.hasNextCallSeq()) {
+            rsh.rollbackNextCallSeq();
+          }
+          throw e;
         } finally {
           // We're done. On way out re-add the above removed lease.
           // Adding resets expiration time on lease.
